home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / prog_gen / gcoope10.zip / GENLIST.C < prev    next >
Text File  |  1994-07-22  |  6KB  |  219 lines

  1. /*
  2.  
  3.     generic function list manager for GCOOPE version 1.0
  4.  
  5.             by Brian Lee Price
  6.  
  7.     Released as Public Domain  July, 1994.
  8.  
  9.     These routines handle GCOOPE's virtual/overloaded/polymorphic/
  10.     generic functions, all generic function dispatching uses the
  11.     lists set up and accessed through them.
  12.  
  13.     Please examine gcstruct.h and listmgr.c prior to any serious
  14.     review of the source code presented here.
  15.  
  16. */
  17.  
  18. #define __GENERICS__
  19.  
  20. #include "gcstruct.h"
  21.  
  22. #include <stdlib.h>
  23. #include <mem.h>
  24.  
  25. /*
  26. AVAILABLE FOR EXTERNAL USE:
  27.  
  28.     Tag compare routine is designed for use with qsort and bsearch.
  29.  
  30. */
  31.  
  32. int tagCmp(const void * ptrA, const void * ptrB)
  33. {
  34. return *((const tag *) ptrA)-*((const tag *) ptrB);
  35. }
  36.  
  37.  
  38. /*
  39. FOR KERNAL USE ONLY!
  40.  
  41. usage:
  42.     newGenericFunctionIndex = addGeneric(default_method);
  43.  
  44.     The dynList polyTable is actually an unordered list of ordered
  45.     lists, the generic function index is used to find the appropriate
  46.     ordered list containing the method dispatching info for that
  47.     generic function.  On a failure this routine returns the value
  48.     MAX_GEN.
  49. */
  50.  
  51. generic addGeneric(method defMthd)
  52. {
  53. int         x;
  54. genEntry *     genList;
  55.  
  56. if((x=addItem(&genTable, sizeof(genEntry)))<0) return MAX_GEN;
  57. genList=genTable.listPtr;
  58. genList+=x;
  59. genList->elemSize=sizeof(genMethod);
  60. genList->defMthd=defMthd;
  61. return x;
  62. }
  63.  
  64. /*
  65. FOR KERNEL USE ONLY!
  66.  
  67. usage:
  68.     genItemElemSize=rmvVirtFunc(generic_type_generic_function_to_remove);
  69.  
  70.     Here you find the common way of accessing a generic function, that
  71.     method is by the tag variable of type generic for the generic function.
  72.     This value is actually an index to genTable.
  73.     Note that this routine uses the return value setup as in the listmgr
  74.     function rmvItem, NOT the FUNCOKAY/FUNCFAIL value.
  75. */
  76.  
  77. int rmvGeneric(generic genFunc)
  78. {
  79. genEntry * genList;
  80.  
  81. if(genFunc>=genTable.maxElems || genFunc<0) return -1;
  82. genList=genTable.listPtr;
  83. genList+=genFunc;
  84. if(genList->listPtr!=NULL)
  85.     s_free(genList->listPtr);
  86. return rmvItem(&genTable, genFunc);
  87. }
  88.  
  89. /*
  90. FOR KERNEL USE ONLY.
  91.  
  92. usage:
  93.     genericFunctionEntryPtr=getMthd(generic_type_function,
  94.     class_tag_value_of_class_for_method_lookup);
  95.  
  96.     This is the core routine for generic function dispatching,
  97.     given a generic function index value and a class tag value
  98.     (see objList.c for an explanation of class tags), this routine
  99.     will return a pointer to the generic list entry in the generic
  100.     list indexed by the generic function index value and looked up
  101.     via. bsearch with the class tag value used as the key.  The
  102.     reason this routine does not just return the method pointer is
  103.     because some possible future enhancements could result in
  104.     additional information being stored in the generic list entry
  105.     structure.
  106.  
  107. */
  108.  
  109.  
  110. genMethod * getMthd(generic genFunc, int clsTag)
  111. {
  112. genEntry * genList;
  113.  
  114. if(genFunc>=genTable.maxElems || genFunc<0) return NULL;
  115. genList=genTable.listPtr;
  116. genList+=genFunc;
  117.  
  118. return bsearch(&clsTag,genList->listPtr,genList->firstFree,
  119.     sizeof(genMethod), tagCmp);
  120. /*
  121.     Note that this function will return NULL on an error, the return
  122.     value of this function ABSOLUTELY MUST be validated or you are
  123.     guaranteed a spectacular program crash!
  124. */
  125. }
  126.  
  127.  
  128.  
  129.  
  130. /*
  131. FOR KERNEL USE ONLY!
  132.  
  133.     usage:
  134.     functionStatus=addMethod(generic_type_function,
  135.         type_method_method_pointer, method_class_tag_value,
  136.         child_class_tag_value);
  137.     Things are getting tricky, this routine installs a method given
  138.     by addMthd into the generic function list given by genFunc,
  139.     for the calling class given by clsTag.  The value owner may
  140.     (or may not) be used by the function dispatcher, however it
  141.     is the class tag of the actual owning class of the method while
  142.     clsTag is (possibly) an class which inherits the method.
  143.     An easy to miss feature of this routine is that it will
  144.     overwrite a previous entry for the same generic function and
  145.     calling class.  The reason is that methods are installed in the
  146.     reverse order of inheritance, thus it is possible for an
  147.     inheriting class to replace a method defined in a superClass.
  148.     This function uses the (standard ???) FUNCFAIL/FUNCOKAY
  149.     return values.
  150. */
  151.  
  152. stat addMethod(generic genFunc, method addMthd,
  153.         tag clsTag, tag owner)
  154. {
  155. int         x;
  156. genEntry *     genList;
  157. genMethod *     methPtr;
  158.  
  159. if(addMthd==(method) NULL || genFunc>=genTable.maxElems || genFunc<0)
  160.     return FUNCFAIL;
  161. genList=genTable.listPtr;
  162. genList+=genFunc;
  163. if(NULL!=(methPtr=bsearch(&clsTag, genList->listPtr, genList->firstFree,
  164.     sizeof(genMethod), tagCmp)))
  165.     {
  166.     methPtr->instMethod=addMthd;
  167.     methPtr->owner=owner;
  168.     return FUNCOKAY;
  169.     }
  170.  
  171. if((x=addItem(genList, sizeof(genMethod)))<0) return FUNCFAIL;
  172. methPtr=genList->listPtr;
  173. methPtr+=x;
  174. methPtr->class=clsTag;
  175. methPtr->owner=owner;
  176. methPtr->instMethod=addMthd;
  177. qsort(genList->listPtr, genList->firstFree, sizeof(genMethod), tagCmp);
  178. return FUNCOKAY;
  179. }
  180.  
  181.  
  182.  
  183. /*
  184. FOR KERNEL USE ONLY.
  185.  
  186. usage:
  187.    functionStatus=rmvMethod(type_generic_function, calling_class_tag,
  188.                 owning_class_tag);
  189.  
  190.    This function will remove a method from a generic function's list.
  191.    It is designed to be called during class removal.  It returns the
  192.    semi-standard FUNCFAIL/FUNCOKAY status value.
  193. */
  194.  
  195. stat rmvMethod(generic genFunc, tag clsTag)
  196. {
  197. genEntry *     genList;
  198. genMethod *     methPtr;
  199. stat        retVal=FUNCFAIL;
  200.  
  201. if(genFunc>=genTable.maxElems || genFunc<0) goto end;
  202. genList=genTable.listPtr;
  203. genList+=genFunc;
  204.  
  205. if(genList->listPtr==NULL) goto end;
  206. if((methPtr=bsearch(&clsTag,genList->listPtr,genList->firstFree,
  207.     sizeof(genMethod), tagCmp))==NULL) goto end;
  208. memset(methPtr,0x,sizeof(genMethod));
  209. genList->firstFree=(int) ((methPtr - genList->listPtr)/genList->elemSize);
  210. compactList(genList, TRUE);
  211.  
  212. retVal=FUNCOKAY;
  213.  
  214. end:
  215. return retVal;
  216. }
  217.  
  218.  
  219.